use std::fs::File;
use std::io::Read;
use std::path::PathBuf;
use serde_derive::Deserialize;
use glob::glob;
use log::{debug, trace};

#[derive(Deserialize, Debug)]
pub struct TaskConfig {
    pub name: Option<String>,
    pub required: Option<Vec<String>>,
    pub cmds: Option<Vec<String>>
}

#[derive(Deserialize, Debug)]
struct Confs {
    task: Option<Vec<TaskConfig>>
}

#[derive(Debug)]
pub struct TaskConfs {
    pub task_configs: Vec<TaskConfig>
}

impl TaskConfs {
    pub fn new() -> Self {
        Self {
            task_configs: Vec::new()
        }
    }

    pub fn read_confs(self: &mut Self, file_path: PathBuf) {
        let mut file = match File::open(file_path) {
            Ok(f) => f,
            Err(e) => panic!("Error occurred when opening file. Exception: {}", e)
        };
        let mut str_val = String::new();
        match file.read_to_string(&mut str_val) {
            Ok(s) => s,
            Err(e) => panic!("Error occurred when reading file. Exception: {}", e)
        };
        let config: Confs = toml::from_str(&str_val).unwrap();
        if let Some(cfgs) = config.task {
            for c in cfgs {
                trace!("Task configuration {:?}", c);
                self.task_configs.push(c);
            }
        }
    }

    pub fn read_confs_from_dir(self: &mut Self, dir: PathBuf) {
        let mut d = dir;
        d.push("**");
        d.push("*.conf");
        for entry in glob(d.to_str().unwrap()).expect("Glob Failed!") {
            match entry {
                Ok(fp) => {
                    debug!("Configuration file path: {:?}", fp.display());
                    self.read_confs(fp);
                },
                Err(e) => panic!("Failed to read files. Exception: {}", e)
            }
        }
    }

    pub fn len(self: &Self) -> usize {
        self.task_configs.len()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_read_confs_from_dir() {
        let mut tc = TaskConfs::new();
        tc.read_confs_from_dir(PathBuf::from("./configs"));
        assert_eq!(4, tc.len());
    }

    #[test]
    fn test_read_confs() {
        let mut tc = TaskConfs::new();
        tc.read_confs(PathBuf::from("./configs/sleep.conf"));
        assert_eq!(4, tc.len());
    }
}